/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_PHYSICTOOLS_H
#define M_PHYSICTOOLS_H

#include "common.h"
#include "vector3.h"
#include "matrix4.h"

namespace Engine
{

	/**
	*   Types of Forces.  Used when creating a Force struct to designate how the Forces should be applied to a Solid.
	*/
	enum ForceType
	{
		FT_FORCE,
		FT_TORQUE
	};

	/**
	*  Data structure containing all necessary info for applying a force/torque to a Solid.
	*/
	class Force
	{
	public:
		Force()
		{
			type = FT_FORCE;
			duration = 0;
			singleStep = false;
		}

		/**
		*   Specifies the type of force.
		*/
		ForceType type;

		/// Specifies how long to apply to force.  This makes it easy to
		/// apply forces independent of the step size.  This will be ignored
		/// if "singleStep" is true.
		REAL duration;

		/**
		*   It specifies that the force will be applied across a single time step.  If this
		*   parameter is true, "duration" will be ignored.
		*/
		bool singleStep;

		/**
		*  The force direction or torque axis.  This parameter encodes the magnitude of the force or torque.
		*/
		Vector3<REAL> vec;
	};

	/**
	*   Data structure describing material properties.  These properties
	*   determine the collision response when two Solids collide.
	*/
	class PhysicMaterial
	{
	public:
		PhysicMaterial(REAL h, REAL f, REAL b, REAL d)
		{
			hardness = h;
			friction = f;
			bounciness = b;
			density = d;
		}

		PhysicMaterial()
		{
			hardness = 0.5;
			friction = 0.5;
			bounciness = 0.5;
			density = 0.5;
		}

		/**
		*   Determines how far Solids can interpenetrate.  This must be between 0 and 1.
		*/
		REAL hardness;

		/**
		*   Simple friction constant.  This must be between 0 and 1.
		*/
		REAL friction;

		/**
		*   Bounciness (i.e. restitution) determines how elastic the
		*   collisions will be between this Material and another.  In other
		*   words, the more bounciness, the farther the Solids will bounce
		*   when they collide (and, in real life, the less energy is lost
		*   due to heat and sound).  This must be between 0 and 1.
		*/
		REAL bounciness;

		/**
		*  Density combined with the volume of a Solid's shapes determine the Solid's mass.  This must be >= 0.
		*/
		REAL density;
	};

	/**
	*    Data structure describing solids mass.
	*/
	class Mass
	{
	public:
        Mass()
        {
            mass = 1;
			center = Vector3<REAL>::ZERO;
			inertia = Matrix4<REAL>::IDENTITY;
            inertia[0][0] = 1 / 6.0;
			inertia[1][1] = 1 / 6.0;
			inertia[2][2] = 1 / 6.0;
        }

		void MakeBox(REAL m, REAL x, REAL y, REAL z)
		{
			mass = x * y * z * m;
			center = Vector3<REAL>::ZERO;
			inertia = Matrix4<REAL>::IDENTITY;
			inertia[0][0] = mass/12.0 * (y*y + z*z);
			inertia[1][1] = mass/12.0 * (x*x + z*z);
			inertia[2][2] = mass/12.0 * (x*x + y*y);
		}

        /**
		*  Total mass of the rigid body. Default is 1.
        */
        REAL mass;

        /**
		*  Center of gravity position in body frame (x,y,z). Default is (0,0,0)
		*/
        Vector3<REAL> center;

        /**
		*  Inertia tensor in body frame, about POR. Default is inertia of a box.
        */
        Matrix4<REAL> inertia;
	};
}

#endif
